/*
 * Copyright (c) 2024 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef __UAPI_IPC_BUFFER_H__
#define __UAPI_IPC_BUFFER_H__

#include "bootinfo.h"
#include "fault.h"

#define IPC_MAX_MSGWORDS (256)

typedef union ip_ipcbuffer {
    bootinfo_t bi;

    struct m_msgs {
        unsigned long cptr;

        unsigned long tag;

        unsigned long msgs[IPC_MAX_MSGWORDS];

        fault_backup_t backup;
    } msgs;
} ipcbuffer_t;

static inline unsigned long msgtag_get_len(unsigned long tag)
{
    return (tag >> 16) & 0x3ffUL;
}

static inline unsigned long msgtag_get_info(unsigned long tag)
{
    return tag & 0xffffUL;
}

static inline unsigned long msgtag_set_info(unsigned long tag, unsigned short info)
{
    tag &= ~(0xffffUL);
    tag |= info;

    return tag;
}

#define msgtag_get_op(tag)     msgtag_get_info(tag)
#define msgtag_get_id(tag)     msgtag_get_info(tag)
#define msgtag_set_op(tag, op) msgtag_set_info(tag, op)
#define msgtag_set_id(tag, op) msgtag_set_info(tag, op)

static inline unsigned long msgtag_get_extra(unsigned long tag)
{
    return (tag >> 26) & 0x3fffffffffULL;
}

static inline unsigned long msgtag_set_extra(unsigned long tag, unsigned char extra)
{
    tag &= ~(0xfffffffffc000000ULL);
    tag |= extra << 26;

    return tag;
}

static inline unsigned long msgtag_make(unsigned char len, unsigned short id_op, unsigned char extra)
{
    return (extra << 26) | (len << 16) | id_op;
}

static inline unsigned long *ipcbuffer_get_msgs(ipcbuffer_t *buf)
{
    return buf->msgs.msgs;
}

static inline void ipcbuffer_set_msgs(ipcbuffer_t *buf, unsigned int index, unsigned long value)
{
    buf->msgs.msgs[index] = value;
}

static inline unsigned long ipcbuffer_get_cptr(ipcbuffer_t *buf)
{
    return buf->msgs.cptr;
}

static inline unsigned char ipcbuffer_get_msglen(ipcbuffer_t *buf)
{
    return msgtag_get_len(buf->msgs.tag);
}

static inline unsigned short ipcbuffer_get_id(ipcbuffer_t *buf)
{
    return msgtag_get_id(buf->msgs.tag);
}

static inline unsigned long ipcbuffer_get_tag(ipcbuffer_t *buf)
{
    return buf->msgs.tag;
}

static inline void ipcbuffer_set_cptr(ipcbuffer_t *buf, unsigned long cptr)
{
    buf->msgs.cptr = cptr;
}

static inline void ipcbuffer_set_tag(ipcbuffer_t *buf, unsigned char msglen, unsigned short info, unsigned char extra)
{
    buf->msgs.tag = msgtag_make(msglen, info, extra);
}

static inline void ipcbuffer_save(ipcbuffer_t *buf, unsigned long tag, unsigned long m0, unsigned long m1,
                                  unsigned long m2, unsigned long m3, unsigned long m4, unsigned long m5)
{
    buf->msgs.tag     = tag;
    buf->msgs.msgs[0] = m0;
    buf->msgs.msgs[1] = m1;
    buf->msgs.msgs[2] = m2;
    buf->msgs.msgs[3] = m3;
    buf->msgs.msgs[4] = m4;
    buf->msgs.msgs[5] = m5;
}

void ipcbuffer_partial_transfer(void *_dst, void *_src, unsigned long tag);
void ipcbuffer_regs_transfer(void *_dst, unsigned long tag, unsigned long m0, unsigned long m1, unsigned long m2,
                             unsigned long m3, unsigned long m4, unsigned long m5);
void ipcbuffer_full_transfer(void *_dst, void *_src);

#endif
